# 自定义jwt的载荷内容
import re

from django.contrib.auth.hashers import make_password
from django_redis import get_redis_connection
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework import serializers
from users.models import UserModel


class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        # 获取默认的token,super()表示调用父类的get_token方法
        token = super().get_token(user)
        # 添加额外的自定义数据到token中
        token['id'] = user.id
        token['username'] = str(user.username)
        token['avatar'] = str(user.avatar)
        token['mobile'] = str(user.mobile)
        token['email'] = str(user.email)
        token['nickname'] = str(user.nickname)
        return token


# 编写注册的序列化器
class RegisterSerializer(serializers.ModelSerializer):
    # 再次确认密码
    re_password = serializers.CharField(required=True, write_only=True, min_length=6, max_length=16)
    # 短信验证码
    sms_code = serializers.CharField(required=True, write_only=True, min_length=3, max_length=5)
    # token字段通常用于存储认证令牌，用于验证用户的身份和权限
    # 但仅用于展示，不允许修改。
    token = serializers.CharField(read_only=True)
    # 刷新token
    refresh = serializers.CharField(read_only=True)

    class Meta:
        model = UserModel
        fields = ['password', 're_password', 'mobile', 'sms_code', 'token', 'refresh']
        # extra_kwargs 是一个字典，用于为序列化器中的字段提供额外的配置选项，
        # 这些选项通常不是通过直接在字段定义时传递参数来设置的，而是通过一个名为
        # extra_kwargs的类属性来统一配置。
        extra_kwargs = {
            "mobile": {
                "required": True,
                "write_only": True
            },
            "password": {
                "required": True,
                "write_only": True,
                "min_length": 6,
                "max_length": 16
            }

        }

    # 自定义校验规则
    # 用来校验传来的数据，是否满足业务要求
    # 执行自定义的验证逻辑。它接收一个参数attrs，该参数是一个字典，包含了所有经过初步验证的字段值。
    def validate(self, attrs):
        mobile = attrs.get('mobile', None)
        # 验证手机号是否合法,如果不合法，则抛出异常
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            raise serializers.ValidationError(detail="手机号格式错误", code="mobile")
        # 否则手机号校验通过
        print('----手机号校验通过----')

        # 验证两次输入的密码是否一致
        password = attrs.get('password')
        re_password = attrs.get('re_password')
        if password != re_password:
            raise serializers.ValidationError(detail="两次输入的密码不一致", code="password")
        # 否则两次输入的密码一致校验通过
        print('----两次输入的密码校验通过----')

        # 验证短信验证码是否正确
        sms_code = attrs.get('sms_code')
        # 获取redis连接，链接sms库
        redis = get_redis_connection('sms')
        # 从redis中获取验证码
        # redis.get()返回的是一个bytes(字节)类型，需要转换成str类型
        code = redis.get(f'sms_{mobile}')


        print(f'---验证码是:{code}')

        if code is None:
            raise serializers.ValidationError(detail="验证码已过期", code="sms_code")
        if code.decode() != sms_code:
            raise serializers.ValidationError(detail="验证码错误", code="sms_code")
        print('----验证码校验通过----')
        # 删除redis数据库中的验证码
        redis.delete(f'sms_{mobile}')

        # 程序健壮性考虑，再次判断一次用户是否存在
        try:
            UserModel.objects.get(mobile=mobile)
            raise serializers.ValidationError(detail="手机号已存在", code="mobile")
        except UserModel.DoesNotExist:
            print('----手机号未被使用----')

        # 校验通过，删除字典中不必要的字段：验证码和第二次输入的密码
        attrs.pop('sms_code')
        attrs.pop('re_password')
        return attrs

    # 重写create方法，完成注册功能
    def create(self, validated_data):
        mobile = validated_data.get('mobile')
        password = validated_data.get('password')
        userinfo = UserModel.objects.create_user(
            mobile=mobile,
            password=password,
            username=mobile,
            avatar='avatar/1.jpg'

        )
        print('----注册成功,手动签发token----')
        refresh = CustomTokenObtainPairSerializer.get_token(user=userinfo)
        print('----刷新token----')
        userinfo.refresh = str(refresh)
        userinfo.token = str(refresh.access_token)
        return userinfo

class SmsLoginSerializer(serializers.ModelSerializer):
    mobile = serializers.CharField(required=True, write_only=True, min_length=11, max_length=11)
    sms_code = serializers.CharField(required=True, write_only=True, min_length=4, max_length=6)
    token = serializers.CharField(read_only=True)
    refresh = serializers.CharField(read_only=True)
    class Meta:
        model = UserModel
        fields = ('mobile', 'sms_code', 'token', 'refresh')

    def validate(self, attrs):
        mobile = attrs.get('mobile')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            raise serializers.ValidationError(detail="手机号格式错误", code="mobile")

        sms_code = attrs.get('sms_code')
        redis = get_redis_connection('sms')
        code = redis.get(f'sms_{mobile}')

        if code is None:
            raise serializers.ValidationError(detail="验证码已过期", code="sms_code")
        if code.decode() != sms_code:
            raise serializers.ValidationError(detail="验证码错误", code="sms_code")

        redis.delete(f'sms_{mobile}')

        # 查找用户
        user = UserModel.objects.filter(mobile=mobile).first()
        if user is None:
            # 如果用户不存在，创建新用户
            user = UserModel.objects.create_user(
                mobile=mobile,
                username=mobile,
                password="123456",  # 默认密码
                avatar='avatar/1.jpg'
            )
            print('----用户不存在,创建用户成功----')
        else:
            print('----用户存在,可以登录----')

        attrs['user'] = user  # 将用户对象添加到 attrs 中
        attrs.pop('sms_code')  # 删除短信验证码
        return attrs

    def create(self, validated_data):
        user = validated_data['user']
        refresh = CustomTokenObtainPairSerializer.get_token(user=user)
        print('----登录成功,手动签发token----')
        print('----刷新token----')
        user.refresh = str(refresh)
        user.token = str(refresh.access_token)
        print(user.refresh)
        print(user.token)
        print(user)
        return user


# 首页页面显示头像
class UserInfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserModel
        fields = ('id', 'username', 'avatar', 'nickname', 'mobile', 'email')